package networkpolicy

import (
    "fcs-api/src/app/model"
    "fcs-api/src/client/kubernetes"
    "strings"

    "git.inspur.com/x/common/loggerfactory"
    corev1 "k8s.io/api/core/v1"
    networkingv1 "k8s.io/api/networking/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/util/intstr"
)

var logger = loggerfactory.GetLogger()

func CreateDefaultPolicy(fcClient *kubernetes.FcClient, namespace string) error {
    // DNS服务的协议和端口
    protocol := corev1.ProtocolUDP
    kongprotocol := corev1.ProtocolTCP
    port := intstr.FromInt(53)
    kongport := intstr.FromInt(8000)

    var peers []networkingv1.NetworkPolicyPeer
    for _, ip := range strings.Split(model.Base.NetworkpolicyWhitelistIp, ",") {
        peer := networkingv1.NetworkPolicyPeer{
            IPBlock: &networkingv1.IPBlock{CIDR: ip + "/32"},
        }
        peers = append(peers, peer)
    }
    policy := &networkingv1.NetworkPolicy{
        ObjectMeta: metav1.ObjectMeta{Name: "default"},
        Spec: networkingv1.NetworkPolicySpec{
            Egress: []networkingv1.NetworkPolicyEgressRule{{
                Ports: []networkingv1.NetworkPolicyPort{{
                    Protocol: &protocol, Port: &port,
                },
                },
                To: []networkingv1.NetworkPolicyPeer{{
                    IPBlock: &networkingv1.IPBlock{CIDR: "0.0.0.0/0"}, // 允许任意地址的DNS服务
                },
                },
            }, {
                Ports: []networkingv1.NetworkPolicyPort{{
                    Protocol: &kongprotocol, Port: &kongport,
                },
                },
                To: []networkingv1.NetworkPolicyPeer{{
                    NamespaceSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"knative": "gateway"}}, // kong地址
                },
                },
            },
                {
                    To: peers,
                },
            },
            PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeEgress},
        },
    }
    logger.Info("CreateDefaultPolicy: creating default networkpolicy for ns %s", namespace)
    _, err := fcClient.CreateNetworkPolicy(namespace, policy)
    if err != nil {
        _ = logger.Error("CreateDefaultPolicy: creating networkpolicy for ns %s error %s", namespace, err.Error())
    }
    return err
}

func CreateFunctionPublicPolicy(fcClient *kubernetes.FcClient, namespace string) error {
    except := []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "100.64.0.0/22"}
    // 如果配置里面配置了地址，就使用这个
    if model.Base.FunctionBlockCidr != "" {
        except = strings.Split(model.Base.FunctionBlockCidr, ",")
    }

    policy := &networkingv1.NetworkPolicy{
        ObjectMeta: metav1.ObjectMeta{Name: "public"},
        Spec: networkingv1.NetworkPolicySpec{
            Egress: []networkingv1.NetworkPolicyEgressRule{{
                To: []networkingv1.NetworkPolicyPeer{{
                    IPBlock: &networkingv1.IPBlock{
                        CIDR:   "0.0.0.0/0",
                        Except: except,
                    },
                }},
            },
            },
            PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeEgress},
            // 匹配标签
            PodSelector: metav1.LabelSelector{
                MatchLabels: map[string]string{
                    model.PublicLabelKey: "true",
                },
            },
        },
    }
    logger.Info("CreateFunctionPublicPolicy: creating networkpolicy for ns %s", namespace)
    _, err := fcClient.CreateNetworkPolicy(namespace, policy)
    if err != nil {
        _ = logger.Error("CreateFunctionPublicPolicy: creating networkpolicy for ns %s error %s", namespace, err.Error())
    }
    return err
}

func CreateVpcNetworkPolicy(fcClient *kubernetes.FcClient, namespace, functionName, versionName, cidr string) error {
    policy := &networkingv1.NetworkPolicy{
        ObjectMeta: metav1.ObjectMeta{Name: functionName + "-" + strings.ToLower(versionName)},
        Spec: networkingv1.NetworkPolicySpec{
            PodSelector: metav1.LabelSelector{
                MatchLabels: map[string]string{
                    model.FunctionNameLabelKey: functionName,
                    model.VersionLabelKey:      versionName,
                },
            },
            Egress: []networkingv1.NetworkPolicyEgressRule{{
                To: []networkingv1.NetworkPolicyPeer{{
                    IPBlock: &networkingv1.IPBlock{CIDR: cidr}, // 管理侧回调地址
                },
                },
            },
            },
            PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeEgress},
        },
    }
    logger.Info("CreateVpcNetworkPolicy: creating vpc networkpolicy for ns %s, function %s", namespace, functionName)
    _, err := fcClient.CreateNetworkPolicy(namespace, policy)
    if err != nil {
        _ = logger.Error("CreateVpcNetworkPolicy: creating networkpolicy for ns %s , function %s error %s", namespace, functionName, err.Error())
        return err
    }
    return nil
}

func DeleteVpcNetworkPolicy(fcClient *kubernetes.FcClient, namespace, functionName, versionName string) error {
    policyName := functionName + "-" + strings.ToLower(versionName)
    err := fcClient.DeleteNetworkPolicy(namespace, policyName)
    if err != nil {
        _ = logger.Error("DeleteVpcNetworkPolicy: deleting networkpolicy for ns %s , function %s error %s", namespace, functionName, err.Error())
        return err
    }
    return nil
}
